﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using Microsoft.WindowsAPICodePack.Shell;

namespace My_TV_Manager.Model
{
    public class SeriesSet
    {
        #region Private Data

        private List<Series> series;
        private List<string> seriesNames;

        #endregion

        #region Properties

        public List<Series> Series { get { return series; } }
        public int Size { get { return series.Count; } }
        public List<string> SeriesNames { get { return seriesNames; } }

        #endregion

        #region Constructors

        // Default constructor for tests
        public SeriesSet()
        {
            series = new List<Series>();
            seriesNames = new List<string>();
        }

        // Constructor which loads series info from directory path
        public SeriesSet(string directoryPath)
        {
            series = new List<Series>();
            seriesNames = new List<string>();

            LoadSeriesFromDirectory(directoryPath);
        }

        #endregion

        #region Functions

        // Determine if directory is valid series directory
        private bool IsValidSeries(string path)
        {
            if (Settings.Test) { return true; }

            string[] subDir = Directory.GetDirectories(path);
            if (subDir.Length == 0)
            {
                Console.Out.WriteLine("No subdirectories");
                return false;
            }

            foreach (string sd in subDir)
            {
                string validString = sd.Substring(sd.LastIndexOf('\\') + 1);
                if (validString.Substring(0, 6) != "Season")
                {
                    Console.Out.WriteLine("Invalid subdirectory: " + validString);
                    return false;
                }
            }

            return true;
        }

        // Load series from file path
        private bool LoadSeries(string path)
        {
            if (Settings.Test)
            {
                series.Add(LoadSeriesFromFile(path, true));
                return true;
            }

            if (!IsValidSeries(path))
            {
                Console.Out.WriteLine(path + ": invalid series directory");
                return false;
            }

            // We have a valid series path: get name of the series
            string seriesName = path.Substring(path.LastIndexOf('\\') + 1);

            // Find the last modified timestep to use for the directory
            DateTime seriesLastModified = Directory.GetLastWriteTime(path);
            string[] dir = Directory.GetDirectories(path);
            foreach (string d in dir)
            {
                if (Directory.GetLastWriteTime(d) > seriesLastModified)
                {
                    seriesLastModified = Directory.GetLastWriteTime(d);
                }
            }

            // Attempt to load series data from program data
            Series s = LoadSeriesFromFile(seriesName, true);

            // If series data was loaded and it is more recent than the file system data
            if (s != null && seriesLastModified <= s.LastModified)
            {
                Console.Out.WriteLine(seriesName + ": Loading series from program data");
            }

            // Series data is not in program data or it is out of date
            else
            {
                Console.Out.WriteLine(seriesName + ": Loading series data from file system");

                // Add the new data and save it to program data
                s = new Series(path);
                SaveSeriesToFile(s);
            }

            // Add the series to the set
            series.Add(s);
            seriesNames.Add(s.Name);

            return true;
        }

        // Load series info from directory path
        public void LoadSeriesFromDirectory(string directoryPath)
        {
            // Get all of the series from the specified file system
            if (Settings.OS.Platform == PlatformID.Win32NT)
            {
                string[] dir;
                if (Settings.Test) { dir = Settings.TestList; }
                else
                {
                    if (!Directory.Exists(directoryPath))
                    {
                        Console.Out.WriteLine(directoryPath + ": path does not exist");
                        LoadSeriesFromSave(true);
                        return;
                    }
                    dir = Directory.GetDirectories(directoryPath);
                }

                foreach (string d in dir)
                {
                    LoadSeries(d);
                }
            }
        }

        // Load series info from TVDB
        public void LoadSeriesFromTVDB(List<string> seriesNames)
        {
            Console.Out.WriteLine("SeriesNames.Size = " + seriesNames.Count);
            foreach (string seriesName in seriesNames)
            {
                Series s = TVDB.GetSeriesInfo(Conversion.SeriesLocalToTVDB(seriesName));

                series.Add(s);
                SaveSeriesToFile(s);
                this.seriesNames.Add(s.Name);
            }
        }

        // Load series from saved series data when input directory is not available
        private void LoadSeriesFromSave(bool isDirectorySeries)
        {
            string directoryPath = Settings.DataDirectory;
            if (isDirectorySeries) { directoryPath += "\\Local"; }
            else { directoryPath += "\\TVDB"; }

            string[] files = Directory.GetFiles(directoryPath);

            foreach (string file in files)
            {
                string seriesName = file.Substring(file.LastIndexOf('\\') + 1, file.Length - file.LastIndexOf('\\') - 5);
                series.Add(LoadSeriesFromFile(seriesName, true));
                seriesNames.Add(seriesName);
            }
        }

        // Load series data from file using serialization
        private Series LoadSeriesFromFile(string seriesName, bool isDirectorySeries)
        {
            string loadDirectory = Settings.DataDirectory;
            if (isDirectorySeries) { loadDirectory += "\\Local"; }
            else { loadDirectory += "\\TVDB"; }

            string filePath = loadDirectory + "\\" + seriesName + ".dat";
            if (!File.Exists(filePath)) { return null; }

            Stream stream = File.Open(filePath, FileMode.Open);
            BinaryFormatter bf = new BinaryFormatter();
            Series loaded = (Series)bf.Deserialize(stream);
            stream.Close();

            return loaded;
        }

        // Save series data to file using serialization
        private void SaveSeriesToFile(Series series)
        {
            string saveDirectory = Settings.DataDirectory;
            if (series.IsDirectorySeries) { saveDirectory += "\\Local"; }
            else { saveDirectory += "\\TVDB"; }

            Stream stream = File.Open(saveDirectory + "\\" + series.Name + ".dat", FileMode.Create);
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(stream, series);
            stream.Close();
            Console.Out.WriteLine("Wrote " + series.Name + " series data to file");
        }

        #endregion
    }
}
